<?php

namespace app\shop\library\pay\implements;

use app\shop\library\pay\PayInterface;
use app\shop\library\ShopAuth;
use app\shop\library\ShopHelper;
use Exception;
use Yansongda\Artful\Exception\ContainerException;
use Yansongda\Artful\Exception\InvalidParamsException;
use Yansongda\Artful\Exception\ServiceNotFoundException;
use Yansongda\Pay\Pay;
use Yansongda\Pay\Provider\Alipay;

class AlipayImplement implements PayInterface
{
    /**
     * 支付配置
     * @var array
     */
    private array $config;

    public function __construct()
    {
        $payConfig = ShopHelper::get_setting_group('alipay');

        $this->config = [
            'alipay' => [
                'default' => [
                    // 必填-支付宝分配的 app_id
                    'app_id'                  => $payConfig['alipay_app_id'],
                    // 必填-应用私钥 字符串或路径
                    // 在 https://open.alipay.com/develop/manage 《应用详情->开发设置->接口加签方式》中设置
                    'app_secret_cert'         => $payConfig['alipay_app_secret_cert'],
                    // 必填-应用公钥证书 路径
                    'app_public_cert_path'    => $payConfig['alipay_app_public_cert_path'],
                    // 必填-支付宝公钥证书 路径
                    'alipay_public_cert_path' => $payConfig['alipay_public_cert_path'],
                    // 必填-支付宝根证书 路径
                    'alipay_root_cert_path'   => $payConfig['alipay_root_cert_path'],
                    'notify_url'              => '',
                    'return_url'              => '',
                    // 选填-默认为正常模式。可选为： MODE_NORMAL, MODE_SANDBOX, MODE_SERVICE
                    'mode'                    => Pay::MODE_NORMAL,
                ]
            ],
            'logger' => [
                'enable'   => true,
                'file'     => root_path() . 'runtime/log/alipay/alipay.log', // 请注意权限
                'level'    => app()->isDebug() ? 'debug' : 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                'type'     => 'daily', // optional, 可选 daily， daily 时将按时间自动划分文件.
                'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
            ],
            'http'   => [
                'timeout'         => 10.0,
                'connect_timeout' => 10.0
            ],
        ];
    }

    /**
     * 检查支付用户信息
     * @return void
     * @throws Exception
     */
    private function getPayUser(): void
    {
        $user = ShopAuth::instance()->getUser();

        if (is_null($user)) {
            throw new Exception('支付用户信息异常,请刷新');
        }
    }

    /**
     * 支付
     * @param array $params
     * @return array
     * @throws Exception
     */
    public function pay(array $params): array
    {
        $this->getPayUser();

        $order = [
            '_method'      => 'get',
            'total_amount' => $params['amount'],
            'subject'      => $params['desc'],
        ];

        $order = array_merge($order, $params);

        return [
            'url' => Pay::alipay($this->config)->web($order)->getHeaders()['Location'][0]
        ];
    }

    /**
     * H5支付
     * @param array $params
     * @return array
     * @throws Exception
     */
    public function h5(array $params): array
    {
        $this->getPayUser();

        $order = [
            '_method'      => 'get',
            'out_trade_no' => $params['out_trade_no'],
            'total_amount' => $params['amount'],
            'subject'      => $params['desc'],
            'quit_url'     => $params['quit_url'],
            'return_url'   => $params['return_url'],
        ];

        return [
            'url' => Pay::alipay($this->config)->h5($order)->getHeaders()['Location'][0]
        ];
    }

    /**
     * 退款
     * @param array $params
     * @return array
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function refund(array $params): array
    {
        $order = [
            'out_trade_no'  => $params['out_trade_no'],
            'refund_amount' => $params['refund_amount'],
            '_action'       => $params['_action'],
            '_notify_url'   => $params['_notify_url']
        ];

        $result = Pay::alipay($this->config)->refund($order);

        return $result->toArray();
    }

    /**
     * 设置支付配置
     * @param array $config
     * @return $this
     */
    public function setConfig(array $config): static
    {
        $this->config = array_merge($this->config, ...$config);

        return $this;
    }

    /**
     * 设置支付回调地址
     * @param string $notifyUrl
     * @param string $configGroup
     * @return AlipayImplement
     */
    public function setNotifyUrl(string $notifyUrl, string $configGroup = 'default'): static
    {
        if (filter_var($notifyUrl, FILTER_VALIDATE_URL) === false) {
            $notifyUrl = ShopHelper::full_api_url() . '/' . ltrim($notifyUrl, '/');
        }

        $this->config['alipay'][$configGroup]['notify_url'] = $notifyUrl;

        return $this;
    }

    /**
     * 设置支付成功后跳转地址
     * @param string $returnUrl
     * @param string $configGroup
     * @return AlipayImplement
     */
    public function setReturnUrl(string $returnUrl, string $configGroup = 'default'): static
    {
        if (filter_var($returnUrl, FILTER_VALIDATE_URL) === false) {
            $returnUrl = ShopHelper::full_h5_url() . '/' . ltrim($returnUrl, '/');
        }

        $this->config['alipay'][$configGroup]['return_url'] = $returnUrl;

        return $this;
    }

    /**
     * 获取支付对象
     */
    public function getPayObject(): Alipay
    {
        return Pay::alipay($this->config);
    }

    /**
     * 设置日志文件路径
     * @param string $filPath
     * @return $this
     */
    public function setLogFilePath(string $filPath): static
    {
        $this->config['logger']['file'] = $filPath;

        return $this;
    }

    /**
     * 查询支付状态
     * @param array $params
     * @return array
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function query(array $params): array
    {
        $order = [
            'out_trade_no' => $params['out_trade_no'],
            '_action'      => $params['_action']
        ];

        return Pay::alipay($this->config)->query($order)->toArray();
    }

    /**
     * 查询退款
     * @param array $params
     * @return array
     * @throws ContainerException
     * @throws InvalidParamsException
     * @throws ServiceNotFoundException
     */
    public function queryRefund(array $params): array
    {
        $order = [
            'out_refund_no' => $params['out_trade_no'],
            '_action'       => $params['_action']
        ];

        return Pay::alipay($this->config)->query($order)->toArray();
    }
}
